/*
 * 人人信用管理有限公司版权所有.
 * 
 * @Description:
 * 
 * @author: liyuliang
 * 
 * @date: 20 Apr 2017 10:44:16 am
 * 
 * 注意：本内容仅限于人人信用管理有限公司内部传阅，禁止外泄以及用于其他的商业目的.
 */

package com.rrx360.common.util;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.ParserContext;
import org.springframework.expression.spel.standard.SpelExpressionParser;

/**
 * Helper class used to evaluate SpEL expression.
 * 
 * @author liyuliang
 * 
 */
public class SpelHelper {

  public static void clearCache() {
    cacheMap.clear();
    tmpCacheMap.clear();
    safePropertyMap.clear();
  }

  private static Map<String, Expression> cacheMap = new ConcurrentHashMap();

  private static Map<String, Expression> tmpCacheMap = new ConcurrentHashMap();

  private static Map<String, String> safePropertyMap = new ConcurrentHashMap<String, String>();

  private static ExpressionParser parser = new SpelExpressionParser();

  public static Expression parse(String exp) {
    return parser.parseExpression(exp);
  }

  public static <T> T safeGetProperty(String exp, Object context) {
    if (context == null) {
      return null;
    }
    return (T) safeGetProperty(exp, context, true);
  }

  public static <T> T safeGetProperty(String exp, Object context, boolean cache) {
    if (exp == null) {
      return null;
    }
    if (!cache) {
      String safeExp = getSafePropertyExp(exp);
      return (T) eval(safeExp, context, false);
    } else {
      String safeExp = safePropertyMap.get(exp);
      if (safeExp == null) {
        safeExp = getSafePropertyExp(exp);
        safePropertyMap.put(exp, safeExp);
      }
      return (T) eval(safeExp, context, true);
    }

  }

  private static String getSafePropertyExp(String exp) {
    String[] values = exp.split("\\.");
    StringBuffer buffer = new StringBuffer();
    for (String s : values) {
      buffer.append(s + "?.");
    }
    return buffer.substring(0, buffer.length() - 2);
  }

  public static <T> T eval(Expression exp, Object context) {
    Object value = exp.getValue(context);
    return (T) value;
  }

  public static <T> T eval(String exp, Object context) {
    return (T) eval(exp, context, true);
  }

  public static <T> T eval(String exp, Object context, boolean cache) {
    Expression expression;
    if (cache) {
      expression = cacheMap.get(exp);
      if (expression == null) {
        expression = parse(exp);
        cacheMap.put(exp, expression);
      }
    } else {
      expression = parse(exp);
    }
    Object value = expression.getValue(context);
    return (T) value;
  }

  public static Expression parseTemplate(String template) {
    return parser.parseExpression(template, ParserContext.TEMPLATE_EXPRESSION);
  }

  public static String evalTemplate(Expression template, Object context) {
    return (String) template.getValue(context);
  }

  public static String evalTemplate(String template, Object context) {
    return evalTemplate(template, context, true);
  }

  public static String evalTemplate(String template, Object context, boolean cache) {
    Expression expression;
    if (cache) {
      expression = tmpCacheMap.get(template);
      if (expression == null) {
        expression = parseTemplate(template);
        tmpCacheMap.put(template, expression);
      }
    } else {
      expression = parseTemplate(template);
    }
    Object result = expression.getValue(context);
    if (result == null) {
      return null;
    }
    return result.toString();
  }

}
